#ifndef _ANIMATIONPAYLOAD_H_
#define _ANIMATIONPAYLOAD_H_
#include <SECore/StateMachine/StateMachine.h>
#include <SEAnimation/Entity/AnimationState.h>
#include <unordered_map>

namespace SEngine
{
    class AnimationPayload
    {
    public:
        AnimationPayload();
        void Start(int ms);
        void Stop();
        template<typename Payload, typename... Args>
        AnimationState & CreateState(Args&&... args) {
            auto & state = m_fsm.CreateState<AnimationState>();
            state.AddDescriptor<Payload>(std::forward<Args>(args)...);
            state.SignalGotoNextState.AddSlot([this]() { this->NextState(); return SlotState::Keep; });
            return state;
        }

        template<typename Payload, typename... Args>
        StateEvent & CreateStateEvent(AnimationState& output, AnimationState& input, Args&&... args) {
            auto event = m_fsm.CreateStateEvent(output, input);
            event->AddDescriptor<Payload>(std::forward<Args>(args)...);
            m_events.emplace_back(std::move(event));
            return *m_events.back();
        }
        void ForeachState(std::function<void(AnimationState&)> && fn) { m_fsm.ForeachState([&](State & state) { fn(static_cast<AnimationState&>(state)); }); }
        void ForeachStateEvent(std::function<void(StateEvent&)> && fn) { for (auto & event : m_events) { fn(*event); } }
        void RemoveState(std::function<bool(AnimationState&)> && fn);
        void RemoveStateEvent(std::function<bool(StateEvent&)> && fn);

        template<typename Payload, typename... Args>
        void CreateEntry(Args&&... args) {
            m_entry = CreateState<Payload>(std::forward<Args>(args)...).shared_from_this();
        }
        bool HasEntry() { return !m_entry.expired(); }

    private:
        void NextState();
    private:
        StateMachine m_fsm;
        std::weak_ptr<State> m_entry;
        std::vector<std::unique_ptr<StateEvent>> m_events;
    };
} // namespace SEngine


#endif